package sso.controller;


import bean.UserDTO;
import bean.UserInfo;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.buf.HexUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import sso.redis.RedisClient;
import sso.response.Response;
import sso.service.UserService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.Random;

/**
 * Created by Michael on 2017/10/30.
 */
@Controller
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RedisClient redisClient;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;




    /**
     *  不存在全局会话,用户第一次登陆,   跳转到登录页
     */
    @RequestMapping(value="/login", method = RequestMethod.GET)
    public ModelAndView loginPage(HttpServletRequest request, String cburl) {
        ModelAndView modelAndView  = new ModelAndView("login");
        modelAndView.getModel().put("cburl",cburl);
        return modelAndView;
    }

    @RequestMapping(value="/loginCheck", method = RequestMethod.GET)
    /**
     * cburl 登录成功后的回跳地址
     */
    public void loginCheck(HttpServletRequest request, String cburl,HttpServletResponse response) throws IOException {

        // /校验session是否登陆过
        String token = (String) request.getSession(true).getAttribute("token");
        if(StringUtils.isNotBlank(token)){
            //如果存在全局token, 证明已经登陆过,那么直接返回token值
            if(cburl.contains("?")){
                response.sendRedirect(cburl+"&token="+token);
            }else{
                response.sendRedirect(cburl+"?token="+token);
            }
            return ;
        }else{
            response.sendRedirect("login?cburl="+cburl);
            return ;
        }
    }
    @RequestMapping(value="/loginFail", method = RequestMethod.GET)
    /**
     * cburl  登录失败的地址
     */
    public ModelAndView loginFail(HttpServletRequest request, String result) {
        ModelAndView modelAndView  = new ModelAndView("loginFail");
        modelAndView.getModel().put("result",result);
        return modelAndView;
    }

    @RequestMapping(value="/login", method = RequestMethod.POST)
    //@ResponseBody
    public void login(@RequestParam("username")String username,
                      @RequestParam("password")String password, HttpServletRequest request, String cburl, HttpServletResponse response) throws IOException {
        if(StringUtils.isBlank(cburl)){
            response.sendRedirect("loginFail?result="+ URLEncoder.encode(JSON.toJSONString(Response.CBURL_INVALID)));
            return;
            //return Response.CBURL_INVALID;
        }
        //前端的问题
        int end = cburl.indexOf(",");
        cburl=cburl.substring(0,end);

        //1. 验证用户名密码
        UserInfo userInfo = null;
            userInfo = userService.getUserByName(username);
        if(userInfo==null) {
            response.sendRedirect("loginFail?result="+ URLEncoder.encode(JSON.toJSONString(Response.USERNAME_PASSWORD_INVALID)));
            return;
            //return Response.USERNAME_PASSWORD_INVALID;
        }
        if(!userInfo.getPassword().equalsIgnoreCase(md5(password))) {
            response.sendRedirect("loginFail?result="+  URLEncoder.encode(JSON.toJSONString(Response.USERNAME_PASSWORD_INVALID)));
            return;
            //return Response.USERNAME_PASSWORD_INVALID;
        }


        //2. 生成token
        String token = genToken();

        //3. 缓存用户
        redisClient.set(token, toDTO(userInfo), 3600);

        //登陆成功,创建全局会话
        HttpSession session = request.getSession(true);
        session.setAttribute("token", token);
        ////todo 应该再生成子系统的token, 返回给子系统, 并且将子系统的token1放到token_trace下, 这样方便注销, 同时保护了全局token
        ////使用hash 结构
        //HashOperations hashOperations = redisTemplate.opsForHash();
        //hashOperations.put(token+"_trace","tokenweb1","logoutUrl");


        response.sendRedirect(cburl+"?token="+token);
        //return new LoginResponse(token);
    }

    @RequestMapping(value="/authentication", method = RequestMethod.POST)
    @ResponseBody
    public UserDTO authentication(@RequestHeader("token") String token) throws IOException {
        //String tokenvalue = redisClient.get(token);
        //if(tokenvalue!=null){
        //    response.sendRedirect(cburl+"?token="+tokenvalue);
        //}else{
        //    response.sendRedirect("loginFail?result="+"验证失败");
        //}
        return redisClient.get(token);
    }

    private UserDTO toDTO(UserInfo userInfo) {
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(userInfo, userDTO);
        return userDTO;
    }

    private String genToken() {
        return randomCode("0123456789abcdefghijklmnopqrstuvwxyz", 32);
    }

    private String randomCode(String s, int size) {
        StringBuilder result = new StringBuilder(size);

        Random random = new Random();
        for(int i=0;i<size;i++) {
            int loc = random.nextInt(s.length());
            result.append(s.charAt(loc));
        }
        return result.toString();
    }

    private String md5(String password) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] md5Bytes = md5.digest(password.getBytes("utf-8"));
            return HexUtils.toHexString(md5Bytes);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
